
/**
 * @file convert.c
 * converts external format to internal format
 */

#include "common.h"
#include "a52.h"

static void fmt_convert_from_u8(double *dest[A52_MAX_CHANNELS],
                                const void *vsrc, int nch, int n)
{
    int i, j, ch;
    const uint8_t *src = vsrc;

    for (ch = 0; ch < nch; ch++) {
        double *dest_ch = dest[ch];
        const uint8_t *src_ch = src + ch;
        for (i = 0, j = 0; i < n; i++, j += nch)
            dest_ch[i] = (src_ch[j]-128.0) / 128.0;
    }
}

static void fmt_convert_from_s8(double *dest[A52_MAX_CHANNELS],
                                const void *vsrc, int nch, int n)
{
    int i, j, ch;
    const int8_t *src = vsrc;

    for (ch = 0; ch < nch; ch++) {
        double *dest_ch = dest[ch];
        const int8_t *src_ch = src + ch;
        for(i = 0, j = 0; i < n; i++, j += nch)
            dest_ch[i] = src_ch[j] / 128.0;
    }
}

static void fmt_convert_from_s16(double *dest[A52_MAX_CHANNELS],
                                 const void *vsrc, int nch, int n)
{
    int i, j, ch;
    const int16_t *src = vsrc;

    for (ch = 0; ch < nch; ch++) {
        double *dest_ch = dest[ch];
        const int16_t *src_ch = src + ch;
        for (i = 0, j = 0; i < n; i++, j += nch)
            dest_ch[i] = src_ch[j] / 32768.0;
    }
}

static void fmt_convert_from_s20(double *dest[A52_MAX_CHANNELS],
                                 const void *vsrc, int nch, int n)
{
    int i, j, ch;
    const int32_t *src = vsrc;

    for (ch = 0; ch < nch; ch++) {
        double *dest_ch = dest[ch];
        const int32_t *src_ch = src + ch;
        for (i = 0, j = 0; i < n; i++, j += nch)
            dest_ch[i] = src_ch[j] / 524288.0;
    }
}

static void fmt_convert_from_s24(double *dest[A52_MAX_CHANNELS],
                                 const void *vsrc, int nch, int n)
{
    int i, j, ch;
    const int32_t *src = vsrc;

    for (ch = 0; ch < nch; ch++) {
        double *dest_ch = dest[ch];
        const int32_t *src_ch = src + ch;
        for (i = 0, j = 0; i < n; i++, j += nch)
            dest_ch[i] = src_ch[j] / 8388608.0;
    }
}

static void fmt_convert_from_s32(double *dest[A52_MAX_CHANNELS],
                                 const void *vsrc, int nch, int n)
{
    int i, j, ch;
    const int32_t *src = vsrc;

    for (ch = 0; ch < nch; ch++) {
        double *dest_ch = dest[ch];
        const int32_t *src_ch = src + ch;
        for (i = 0, j = 0; i < n; i++, j += nch)
            dest_ch[i] = src_ch[j] / 2147483648.0;
    }
}

static void fmt_convert_from_float(double *dest[A52_MAX_CHANNELS],
                                   const void *vsrc, int nch, int n)
{
    int i, j, ch;
    const float *src = vsrc;

    for (ch = 0; ch < nch; ch++) {
        double *dest_ch = dest[ch];
        const float *src_ch = src + ch;
        for (i = 0, j = 0; i < n; i++, j += nch)
            dest_ch[i] = src_ch[j];
    }
}

static void fmt_convert_from_double(double *dest[A52_MAX_CHANNELS],
                                    const void *vsrc, int nch, int n)
{
    int i, j, ch;
    const double *src = vsrc;

    for (ch = 0; ch < nch; ch++) {
        double *dest_ch = dest[ch];
        const double *src_ch = src + ch;
        for (i = 0, j = 0; i < n; i++, j += nch)
            dest_ch[i] = (double)src_ch[j];
    }
}

void a52_set_converter(A52Context *ctx, A52SampleFormat sample_format)
{
    switch(sample_format) {
        case A52_SAMPLE_FMT_U8:
            ctx->fmt_convert_from_src = fmt_convert_from_u8;
            break;
        case A52_SAMPLE_FMT_S8:
            ctx->fmt_convert_from_src = fmt_convert_from_s8;
            break;
        case A52_SAMPLE_FMT_S16:
            ctx->fmt_convert_from_src = fmt_convert_from_s16;
            break;
        case A52_SAMPLE_FMT_S20:
            ctx->fmt_convert_from_src = fmt_convert_from_s20;
            break;
        case A52_SAMPLE_FMT_S24:
            ctx->fmt_convert_from_src = fmt_convert_from_s24;
            break;
        case A52_SAMPLE_FMT_S32:
            ctx->fmt_convert_from_src = fmt_convert_from_s32;
            break;
        case A52_SAMPLE_FMT_FLT:
            ctx->fmt_convert_from_src = fmt_convert_from_float;
            break;
        case A52_SAMPLE_FMT_DBL:
            ctx->fmt_convert_from_src = fmt_convert_from_double;
            break;
    }
}
